package com.erhuogo.util;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;

import org.hibernate.Query;
import org.hibernate.SessionFactory;
import org.hibernate.classic.Session;
import org.hibernate.criterion.Order;

/** 封装dao基类:泛型,HQL,QBC */
public abstract class BaseDao<T> {
	// 封装CURD操作
	private SessionFactory sessionFactory;
	private Class<T> entityClass;// 保存类对象:User.class,Person.class

	@SuppressWarnings("unchecked")
	public BaseDao() {
		// Type是Java语言中所有类型的公共高级接口
		Type type = this.getClass().getGenericSuperclass();// 获得父类的类型

		if (!(type instanceof ParameterizedType)) {
			// 在UserDao被代理的情况下(cglib动态代理),要通过getSuperclass()
			type = this.getClass().getSuperclass().getGenericSuperclass();
		}

		ParameterizedType pType = (ParameterizedType) type;// 获得父类的泛型参数

		this.entityClass = (Class<T>) pType.getActualTypeArguments()[0];// 返回泛型参数的实际类型
	}

	public SessionFactory getSessionFactory() {
		return sessionFactory;
	}

	public void setSessionFactory(SessionFactory sessionFactory) {
		this.sessionFactory = sessionFactory;
	}

	public Session getSession() {
		// return HibernateUtil.getSession();
		return sessionFactory.getCurrentSession();
	}

	public void save(final T entity) {
		getSession().save(entity);
	}

	@SuppressWarnings("unchecked")
	public List<T> query() {
		return (List<T>) getSession().createCriteria(this.entityClass).addOrder(Order.asc("id")).list();
	}

	// 封装查询方法,结果按要求排序:String orderBy, boolean isAsc,hql
	@SuppressWarnings("unchecked")
	public List<T> query(String orderBy, boolean isAsc) {
		String hql = "";
		if (isAsc) {
			hql = String.format("from %s order by %s asc", this.entityClass.getName(), orderBy);
		} else {
			hql = String.format("from %s order by %s desc", this.entityClass.getName(), orderBy);
		}

		return (List<T>) getSession().createQuery(hql).list();
	}

	// 删除表全部记录
	public void delete() {
		String hql = String.format("delete from %s", this.entityClass.getName());

		getSession().createQuery(hql).executeUpdate();
	}

	// 根据id删除
	public <X> void delete(X id) {
		String hql = String.format("delete from %s where id=:id", this.entityClass.getName());
		getSession().createQuery(hql).setParameter("id", id)// 不确定参数类型,就用setParameter()
				.executeUpdate();
	}

	public void update(String hql, final Object... values) {
		Query query = getSession().createQuery(hql);

		if (values != null) {
			for (int i = 0; i < values.length; i++) {
				query.setParameter(i, values[i]);
			}
		}

		query.executeUpdate();
	}

	// 根据hql语句和多个属性进行查询,用变长参数封装属性值,按顺序绑定参数
	// hql:from User where name=? and age=?
	// values:"xiaoli",19
	@SuppressWarnings("unchecked")
	public <X> List<X> query(String hql, final Object... values) {
		Query query = getSession().createQuery(hql);

		if (values != null) {
			for (int i = 0; i < values.length; i++) {
				query.setParameter(i, values[i]);
			}
		}

		List<X> list = query.list();
		return list;
	}

	// 根据hql语句和多个属性进行查询,用集合参数封装属性值,按参数名称绑定参数
	// hql:from User where name=:name and age=:age
	// values:传Map进来
	@SuppressWarnings("unchecked")
	public <X> List<X> query(String hql, final Map<String, ?> values) {
		Query query = getSession().createQuery(hql);

		if (values != null) {
			query.setProperties(values);
		}

		List<X> list = query.list();
		return list;
	}

	// 分页查询
	@SuppressWarnings("unchecked")
	public <X> List<X> queryPage(int firstResult, int maxResults, String hql, final Object... values) {
		Query query = getSession().createQuery(hql);
		if (values != null) {
			for (int i = 0; i < values.length; i++) {
				query.setParameter(i, values[i]);
			}
		}

		List<X> list = query.setFirstResult(firstResult).setMaxResults(maxResults).list();
		return list;
	}

	@SuppressWarnings("unchecked")
	public <X> List<X> queryPage(int firstResult, int maxResults, String hql, final Map<String, ?> values) {
		Query query = getSession().createQuery(hql);

		if (values != null) {
			query.setProperties(values);
		}

		List<X> list = query.setFirstResult(firstResult).setMaxResults(maxResults).list();
		return list;
	}
}
